%define _GATE_EXTERN_OR_GLOBAL_ 1 
%include"../include/gdt.mac" 

[section .text] 
;set descriptor in the gdt 
;input: 
;	 1.limit_low. Low 16 bits limit,word; 
;	 2.base_low. Low 16 bits base,word; 
;	 3.base_mid. Middle 8 bits base,byte; 
;	 4.type_attr. 4 bits bype,4 bits attributes; 
;    5.limit_attr. 4 bits limit,4 bits attributes; 
;	 6.base_high. 1 byte base. 
;	 7.gdt_index. index in the gdt. 
;output:none 

;Used As Near call 

;Stack frame: 
;|limit_low | 
;|base_low  | 
;|base_mid  | 
;|type_attr | 
;|limit_attr| 
;|base_high | 
;|gdt_index | 
;|EIP		|  

;|ebp		| (pushed as frame pointer)   
gdt_set_desc: 
	push ebp 
	mov ebp,esp  ;frame pointer   
	push eax 
	push ebx 
	push ecx 
	
	;get parameter from stack 
	mov ebx,[ebp+8] ;get index  
	shl ebx,3 ;index*8,get offset  from GDT base   

	mov eax,[ebp+32] ;get and fill limit_low  
	mov word[gdt+ebx+descriptor.limit_low],ax 

	mov eax,[ebp+28] ;get and fill base_low   
	mov word[gdt+ebx+descriptor.base_low],ax 

	mov eax,[ebp+24] ;get and fill base_mid  
	mov byte[gdt+ebx+descriptor.base_mid],al 

	mov eax,[ebp+20] ;get and fill type_attr  
	mov byte[gdt+ebx+descriptor.type_attr],al 

	mov eax,[ebp+16] ;get and file limit_attr 
	mov byte[gdt+ebx+descriptor.limit_attr],al 

	mov eax,[ebp+12] ;get and fill base_high 
	mov byte[gdt+ebx+descriptor.base_high],al 

	pop ecx 
	pop ebx 
	pop eax 
	pop ebp 
	ret 28 ;clean up stack  

;set null descriptor(first descriptor in gdt) 
;input:none  
;output:none 
gdt_set_null_desc: 
	push 0 
	push 0 
	push 0 
	push 0 
	push 0 
	push 0 
	push 0 
	call gdt_set_desc ;install 
	ret 

;set kernel code descriptor 
;input:
;	1.index. index in the gdt 
;output:none 

;Used only as near call 
;Stack frame: 
;|index	| 
;|eip	| 

;|ebp	| 
gdt_set_kernel_code_desc: 
	push ebp 
	mov ebp,esp ;stack frame pointer   
	push eax 

	mov eax,[ebp+8] ;get index 

	push LIMIT_640KB_LOW 
	push KERNEL_CODE_BASE_LOW 
	push KERNEL_CODE_BASE_MID 
	push KERNEL_CODE_TYPE_ATTR 
	push KERNEL_CODE_LIMIT_ATTR 
	push KERNEL_CODE_BASE_HIGH 
	push eax 
	call gdt_set_desc 

	pop eax 
	pop ebp 
	ret 4 

;set kernel data descriptor 
;input: 
;	1.index. index in the gdt. 
;output:none 

;Used as only for near call 
;Stack frame: 
;|index	| 
;|eip	| 

;|ebp	|   
gdt_set_kernel_data_desc: 
	push ebp 
	mov ebp,esp 
	push eax 

	mov eax,[ebp+8] ;get index  

	;set 
	push LIMIT_640KB_LOW 
	push KERNEL_DATA_BASE_LOW 
	push KERNEL_DATA_BASE_MID 
	push KERNEL_DATA_TYPE_ATTR 
	push KERNEL_DATA_LIMIT_ATTR 
	push KERNEL_DATA_BASE_HIGH 
	push eax 
	call gdt_set_desc 

	pop eax 
	pop ebp   
	ret 4 ;clean up stack 

;initialize gdt 
;input:none 
;output:none 

;Used as only for near call 
;Stack frame: 
;|eip		| 

init_gdt:
	call gdt_set_null_desc ;null descriptor 

	push KERNEL_CODE_GDT_INDEX ;index  
	call gdt_set_kernel_code_desc ;kernel code segment  

	push KERNEL_DATA_GDT_INDEX ;index  
	call gdt_set_kernel_data_desc ;kernel data segment

	;load gdtr
	LOAD_GDTR load_store_gdtr
	ret

[section .data]
;lgdt [LGDT_ADDR]
load_store_gdtr:
	istruc pseudo_descriptor
		at pseudo_descriptor.limit,dw GDT_LEN 
		at pseudo_descriptor.base,dd gdt
	iend
